#include<iostream>
using namespace std;

/**
 * 一些必须掌握的概念：
 *      1、数组是一片连续的内存，整个数组占用内存大小 = sizeof(数组元素的类型) * 数组元素个数
 *      2、数组中元素的个数计算 = sizeof(数组) / sizeof(数组元素类型)
 *      3、数组的大小是固定的，无论是静态声明还是动态通过new方式创建，一旦创建大小就固定了
 *         作业来了：看下STL中vector的源码，他有个函数叫resize的，看下他在调整数组大小的时候是怎么实现的？应该是整个新申请了一块较大的空间，然后复制旧数据，再释放旧空间这种思路实现的。
 *      4、看下网友的这段描述，是关于数组名和数组本身的关系讲的最清楚的一段话了：
 *         https://www.zhihu.com/question/269753414
 *         今天有学弟问为什么对于一个数组a[10]来说a和&a的值一样，才发现这个问题。。。
 *         c语言里规定在对数组名进行取地址操作时得到的是数组首元素的地址，如果按照正常的理解，数组名就像一个指针，他应该有自己的地址，
 *         但其实数组名本身是没有内存空间的，所以数组名是没有地址的，只有数组元素才有自己的空间和地址，
 *         所以数组名本身就是表示这数组本身，所以你对他取大小，就是数组整体大小，你对他取址得到的就是整个数组的起始位置(也就是首元素的地址)，
 *         但是当你又定义了一个指针指向他的时候，你定义的这个指针是有自己的内存空间的，所以他自己是有地址的，当他指向数组名的时候，
 *         指向的也仅仅是数组的起始位置。它本身是不知道数组的存在的。
 * */

int main() {
    
    //栈上分配的数组，函数局部变量，函数退出自动释放
    int iarr[] = {1,2,3};
    
    //等效于下面的几种声明方式：
    //int iarr[3] = {1,2,3};
    //或者
    /*
    int iarr[3] = {0}; //声明的时候最好初始化下，否则会出现所谓的脏数据问题，这条原则适用于所有变量。
    iarr[0] = 1;
    iarr[2] = 2;
    iarr[3] = 3;
    */

    cout << sizeof(iarr) <<endl;    //12,一个int占4个字节，3个int就是12个字节
    cout << &iarr << endl;          //0x28cd20，看下第四条中说的，对数组名取地址就是取数组首元素的地址，因为数组名本身没有空间（指针有自己的空间，4字节）
    cout << iarr[0] << endl;        //1,通过下标访问数组元素，最快速的访问方式

    int* p = &iarr[0];              //0x28cd20，这里首先p是个int的指针，指向了数组首元素的地址，再看后面的地址观察：

    //接着看p，p本身是有地址空间的，指针类型嘛，占4个字节大小，就是说int* p的时候会分配4个空间的大小给p，p本身是个变量名，它里面存储的是iarr[0]的首地址值
    cout << "p=" << p << endl;      //这里输出的是p存储的值，p本身存储的就是iarr[0]的值，也就是iarr数组的首地址
    cout << *p << endl;             //对p解引用，得到的是iarr[0]，是1
    cout << &p << endl;             //p自己也是个指针类型的变量，占4个字节的大小空间，这里打印的是p本身的地址空间的首地址
                                    //观察&p和p本身是不一样的，是两个内存空间

    return 0;
}
/**
 * $ ./test
*/
